using System;
using System.Globalization;
using Windows.UI.Xaml;
using System.Reflection;
namespace System.Windows.Interactivity
{
	/// <summary>
	/// Represents an attachable object that encapsulates a unit of functionality.
	/// </summary>
	/// <remarks>This is an infrastructure class. Action authors should derive from TriggerAction&lt;T&gt; instead of this class.</remarks>
    //[DefaultTrigger(typeof(UIElement), typeof(EventTrigger), "MouseLeftButtonDown"), DefaultTrigger(typeof(ButtonBase), typeof(EventTrigger), "Click")]
	public abstract class TriggerAction : FrameworkElement, IAttachedObject
	{
		private bool isHosted;
		private DependencyObject associatedObject;
		private Type associatedObjectTypeConstraint;
		public static readonly DependencyProperty IsEnabledProperty = DependencyProperty.Register("IsEnabled", typeof(bool), typeof(TriggerAction), new PropertyMetadata(true));
		/// <summary>
		/// Gets or sets a value indicating whether this action will run when invoked. This is a dependency property.
		/// </summary>
		/// <value>
		/// 	<c>True</c> if this action will be run when invoked; otherwise, <c>False</c>.
		/// </value>
		public bool IsEnabled
		{
			get
			{
				return (bool)base.GetValue(TriggerAction.IsEnabledProperty);
			}
			set
			{
				base.SetValue(TriggerAction.IsEnabledProperty, value);
			}
		}
		/// <summary>
		/// Gets the object to which this action is attached.
		/// </summary>
		/// <value>The associated object.</value>
		protected DependencyObject AssociatedObject
		{
			get
			{
				return this.associatedObject;
			}
		}
		/// <summary>
		/// Gets the associated object type constraint.
		/// </summary>
		/// <value>The associated object type constraint.</value>
		protected virtual Type AssociatedObjectTypeConstraint
		{
			get
			{
				return this.associatedObjectTypeConstraint;
			}
		}
		/// <summary>
		/// Gets or sets a value indicating whether this instance is attached.
		/// </summary>
		/// <value><c>True</c> if this instance is attached; otherwise, <c>False</c>.</value>
		internal bool IsHosted
		{
			get
			{
				return this.isHosted;
			}
			set
			{
				this.isHosted = value;
			}
		}
		/// <summary>
		/// Gets the associated object.
		/// </summary>
		/// <value>The associated object.</value>
		DependencyObject IAttachedObject.AssociatedObject
		{
			get
			{
				return this.AssociatedObject;
			}
		}
		internal TriggerAction(Type associatedObjectTypeConstraint)
		{
			this.associatedObjectTypeConstraint = associatedObjectTypeConstraint;
		}
		/// <summary>
		/// Attempts to invoke the action.
		/// </summary>
		/// <param name="parameter">The parameter to the action. If the action does not require a parameter, the parameter may be set to a null reference.</param>
		internal void CallInvoke(object parameter)
		{
			if (this.IsEnabled)
			{
				this.Invoke(parameter);
			}
		}
		/// <summary>
		/// Invokes the action.
		/// </summary>
		/// <param name="parameter">The parameter to the action. If the action does not require a parameter, the parameter may be set to a null reference.</param>
		protected abstract void Invoke(object parameter);
		/// <summary>
		/// Called after the action is attached to an AssociatedObject.
		/// </summary>
		protected virtual void OnAttached()
		{
		}
		/// <summary>
		/// Called when the action is being detached from its AssociatedObject, but before it has actually occurred.
		/// </summary>
		protected virtual void OnDetaching()
		{
		}
		/// <summary>
		/// When implemented in a derived class, creates a new instance of the <see cref="T:System.Windows.Freezable" /> derived class.
		/// </summary>
		/// <returns>The new instance.</returns>
        //protected override Freezable CreateInstanceCore()
        //{
        //    Type type = base.GetType();
        //    return (Freezable)Activator.CreateInstance(type);
        //}
		/// <summary>
		/// Attaches to the specified object.
		/// </summary>
		/// <param name="dependencyObject">The object to attach to.</param>
		/// <exception cref="T:System.InvalidOperationException">Cannot host the same TriggerAction on more than one object at a time.</exception>
		/// <exception cref="T:System.InvalidOperationException">dependencyObject does not satisfy the TriggerAction type constraint.</exception>
		public void Attach(DependencyObject dependencyObject)
		{
			if (dependencyObject != this.AssociatedObject)
			{
				if (this.AssociatedObject != null)
				{
					throw new InvalidOperationException("CannotHostTriggerActionMultipleTimesExceptionMessage");
				}
				if (dependencyObject != null && !this.AssociatedObjectTypeConstraint.GetTypeInfo().IsAssignableFrom(dependencyObject.GetType().GetTypeInfo()))
				{
					throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, "TypeConstraintViolatedExceptionMessage", new object[]
					{
						base.GetType().Name,
						dependencyObject.GetType().Name,
						this.AssociatedObjectTypeConstraint.Name
					}));
				}
				this.associatedObject = dependencyObject;
				this.OnAttached();
			}
		}
		/// <summary>
		/// Detaches this instance from its associated object.
		/// </summary>
		public void Detach()
		{
			this.OnDetaching();
			this.associatedObject = null;
		}
	}
}
